package service

import (
	"bufio"
	"fmt"
	"gitee.com/daka1004/devops-runner/common/logs"
	"gitee.com/daka1004/devops-runner/dto/request"
	"github.com/saintfish/chardet"
	"golang.org/x/text/encoding"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/encoding/traditionalchinese"
	"golang.org/x/text/transform"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// SoftwareFactoryService 对应Java中的SoftwareFactoryService
type SoftwareFactoryService struct{}

// 获取目录下的指定文件路径（从目录路径拼接）
func getFilePathInDirectory(dirPath, fileName string) (string, error) {
	// 确保目录路径格式统一（替换反斜杠为正斜杠）
	normalizedDir := strings.ReplaceAll(dirPath, "\\", "/")

	// 处理目录末尾的斜杠（兼容有/无斜杠的输入）
	if strings.HasSuffix(normalizedDir, "/") {
		normalizedDir = normalizedDir[:len(normalizedDir)-1]
	}

	// 构建文件路径（使用平台特定的路径分隔符）
	filePath := filepath.Join(normalizedDir, fileName)

	// 获取绝对路径（处理.和..等特殊符号）
	absFilePath, err := filepath.Abs(filePath)
	if err != nil {
		return "", fmt.Errorf("获取绝对路径失败: %w", err)
	}

	return absFilePath, nil
}

// 获取结果文件路径，智能处理目录和文件输入
func getResultPath(inputPath string) (string, error) {
	// 处理空路径
	if inputPath == "" {
		return "", fmt.Errorf("invalid empty path")
	}

	// 标准化路径格式（统一使用操作系统路径分隔符）
	cleanPath := filepath.Clean(inputPath)

	// 检查路径是否存在
	exists, err := pathExists(cleanPath)
	if err != nil {
		return "", fmt.Errorf("failed to check path existence: %w", err)
	}

	// 当路径不存在时，提取目录部分并拼接结果文件
	if !exists {
		dir := filepath.Dir(cleanPath)
		return filepath.Join(dir, "result_path.txt"), nil
	}

	// 当路径存在时，判断是文件还是目录
	isDir, err := isDirectory(cleanPath)
	if err != nil {
		return "", fmt.Errorf("failed to check path type: %w", err)
	}

	// 如果是目录，直接在目录下拼接结果文件
	if isDir {
		return filepath.Join(cleanPath, "result_path.txt"), nil
	}

	// 如果是文件，获取其父目录并拼接结果文件
	parentDir := filepath.Dir(cleanPath)
	return filepath.Join(parentDir, "result_path.txt"), nil
}

// 检查路径是否存在
func pathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err // 其他错误（如权限不足）
}

// 检查路径是否为目录
func isDirectory(path string) (bool, error) {
	info, err := os.Stat(path)
	if err != nil {
		return false, err
	}
	return info.IsDir(), nil
}

// 获取目录下的结果文件路径（直接拼接，不丢失层级）
func getResultPath2(dirPath string) (string, error) {
	// 确保路径格式统一（替换反斜杠为正斜杠）
	normalizedDir := strings.ReplaceAll(dirPath, "\\", "/")

	// 处理空路径或纯分隔符路径
	if normalizedDir == "" || normalizedDir == "/" {
		return "", fmt.Errorf("invalid directory path: %s", dirPath)
	}

	// 分割路径并过滤空元素（处理连续分隔符）
	parts := strings.Split(normalizedDir, "/")
	var validParts []string
	for _, part := range parts {
		if part != "" {
			validParts = append(validParts, part)
		}
	}

	// 确保目录路径有效
	if len(validParts) < 1 {
		return "", fmt.Errorf("invalid directory path: %s", dirPath)
	}

	// 构建结果文件路径（直接拼接）
	resultPath := filepath.Join(normalizedDir, "result_path.txt")

	// 标准化路径（处理.和..等特殊符号）
	absResultPath, err := filepath.Abs(resultPath)
	if err != nil {
		return "", fmt.Errorf("failed to get absolute path: %w", err)
	}

	return absResultPath, nil
}

// ThreeInOneStaticAnalysis 实现三合一静态分析功能
func (s *SoftwareFactoryService) ThreeInOneStaticAnalysis(threeInOneModel request.ThreeInOneModel) request.CommandBean {
	threeInOneBatPath := threeInOneModel.ThreeInOneBatPath
	commandBean := request.CommandBean{}
	fmt.Printf("接收到三合一文件夹路径 ，准备监控 :%s\n", threeInOneBatPath)

	// 获取脚本所在目录
	//path := strings.TrimSuffix(threeInOneBatPath, "/"+strings.Split(threeInOneBatPath, "/")[len(strings.Split(threeInOneBatPath, "/"))-1])
	//resultPath := path + "/result_path.txt"
	resultPath, err := getResultPath(threeInOneBatPath)
	if err != nil {
		logs.Errorf("获取脚本所在目录出错： %v\n", err)
	}
	// 等待并检查 result_path.txt 文件
	fileFound := waitForFileWithTimeout(resultPath, 1*time.Minute)
	if !fileFound {
		fmt.Println("三合一执行失败，result_path.txt文件不存在")
		commandBean.ErrorMsg = "找不到result_path.txt文件"
		return commandBean
	}

	// 读取 result_path.txt 获取 JSON 文件路径
	resultData, err := ioutil.ReadFile(resultPath)
	if err != nil {
		commandBean.ErrorMsg = fmt.Sprintf("读取result_path.txt文件失败: %v", err)
		return commandBean
	}

	// 自动检测 result_path.txt 的编码
	resultCharset, err := detectEncoding(resultData)
	if err != nil {
		fmt.Printf("警告: 检测result_path.txt编码失败，使用默认编码: %v\n", err)
		resultCharset = "UTF-8"
	}
	fmt.Printf("result_path.txt 编码: %s\n", resultCharset)

	// 解码 result_path.txt 内容
	resultContent, err := decodeByCharset(resultData, resultCharset)
	if err != nil {
		fmt.Printf("警告: 使用 %s 解码result_path.txt失败，尝试GB-18030...\n", resultCharset)
		resultContent, err = decodeByCharset(resultData, "GB-18030")
		if err != nil {
			commandBean.ErrorMsg = fmt.Sprintf("解码result_path.txt失败: %v", err)
			return commandBean
		}
	}

	jsonPath := strings.TrimSpace(resultContent)
	if jsonPath == "" {
		commandBean.ErrorMsg = "result_path.txt内容为空"
		return commandBean
	}

	// 等待并检查 JSON 文件
	fileFound = waitForFileWithTimeout(jsonPath, 1*time.Minute)
	if !fileFound {
		fmt.Println("三合一执行失败，AnalysisResult.json文件不存在")
		commandBean.ErrorMsg = "找不到AnalysisResult.json文件"
		return commandBean
	}

	// 读取 JSON 文件内容
	jsonData, err := ioutil.ReadFile(jsonPath)
	if err != nil {
		commandBean.ErrorMsg = fmt.Sprintf("读取AnalysisResult.json文件失败: %v", err)
		return commandBean
	}

	// 自动检测 JSON 文件的编码
	jsonCharset, err := detectEncoding(jsonData)
	if err != nil {
		fmt.Printf("警告: 检测JSON文件编码失败，使用默认编码: %v\n", err)
		jsonCharset = "UTF-8"
	}
	fmt.Printf("JSON 文件编码: %s\n", jsonCharset)

	// 解码 JSON 文件内容
	decodedJSON, err := decodeByCharset(jsonData, jsonCharset)
	if err != nil {
		fmt.Printf("警告: 使用 %s 解码JSON文件失败，尝试GB-18030...\n", jsonCharset)
		decodedJSON, err = decodeByCharset(jsonData, "GB-18030")
		if err != nil {
			fmt.Printf("警告: 使用GB-18030解码失败，尝试GBK...\n")
			decodedJSON, err = decodeByCharset(jsonData, "GBK")
			if err != nil {
				commandBean.ErrorMsg = fmt.Sprintf("解码JSON文件失败: %v", err)
				return commandBean
			}
		}
	}

	commandBean.Report = strings.TrimSpace(decodedJSON)
	return commandBean
}

//// ThreeInOneStaticAnalysis 实现三合一静态分析功能
//func (s *SoftwareFactoryService) ThreeInOneStaticAnalysis(threeInOneModel request.ThreeInOneModel) request.CommandBean {
//	threeInOneBatPath := threeInOneModel.ThreeInOneBatPath
//	commandBean := request.CommandBean{}
//	fmt.Printf("接收到三合一文件夹路径 ，准备监控 :%s\n", threeInOneBatPath)
//
//	path := strings.TrimSuffix(threeInOneBatPath, "/"+strings.Split(threeInOneBatPath, "/")[len(strings.Split(threeInOneBatPath, "/"))-1])
//	resultPath := path + "/result_path.txt"
//
//	fileFound := waitForFileWithTimeout(resultPath, 120*time.Minute)
//	if fileFound {
//		jsonPath, err := readFile(resultPath)
//		if err != nil {
//			commandBean.ErrorMsg = "读取result_path.txt文件失败"
//			return commandBean
//		}
//		jsonPath = strings.TrimSpace(jsonPath)
//
//		fileFound = waitForFileWithTimeout(jsonPath, 120*time.Minute)
//		if fileFound {
//			jsonData, err := readFileWithEncoding(jsonPath, "GB2312")
//			if err != nil {
//				commandBean.ErrorMsg = "读取AnalysisResult.json文件失败"
//				return commandBean
//			}
//			commandBean.Report = strings.TrimSpace(jsonData)
//		} else {
//			fmt.Println("三合一执行失败，AnalysisResult.json文件不存在")
//			commandBean.ErrorMsg = "找不到AnalysisResult.json文件"
//			return commandBean
//		}
//	} else {
//		fmt.Println("三合一执行失败，result_path.txt文件不存在")
//		commandBean.ErrorMsg = "找不到result_path.txt文件"
//		return commandBean
//	}
//
//	return commandBean
//}

// request.CommandBean 结构体，这里假设其定义如下
type CommandBean struct {
	Report   string
	ErrorMsg string
}

// detectEncoding 自动检测文件编码
func detectEncoding(data []byte) (string, error) {
	detector := chardet.NewTextDetector()
	result, err := detector.DetectBest(data)
	if err != nil {
		return "", err
	}

	// 提高 GB-18030 检测准确性
	if result.Charset == "ISO-8859-1" && hasChineseCharacters(data) {
		return "GB-18030", nil
	}

	return result.Charset, nil
}

// hasChineseCharacters 检测是否包含中文字符
func hasChineseCharacters(data []byte) bool {
	for i := 0; i < len(data)-1; i++ {
		// 检查是否可能是 GB-18030/GBK/GB2312 编码的中文字符
		if data[i] >= 0x81 && data[i] <= 0xFE && data[i+1] >= 0x40 && data[i+1] <= 0xFE {
			return true
		}
	}
	return false
}

// decodeByCharset 根据字符集解码数据
func decodeByCharset(data []byte, charset string) (string, error) {
	var decoder *encoding.Decoder

	switch strings.ToUpper(charset) {
	case "UTF-8", "UTF8":
		return string(data), nil
	case "GB-18030", "GB18030":
		decoder = simplifiedchinese.GB18030.NewDecoder()
	case "GBK", "CP936", "GB2312", "EUC-CN":
		decoder = simplifiedchinese.GBK.NewDecoder()
	//case "GB2312", "EUC-CN":
	//decoder = simplifiedchinese.b()
	case "BIG5", "CP950":
		decoder = traditionalchinese.Big5.NewDecoder()
	default:
		return "", fmt.Errorf("不支持的编码: %s", charset)
	}

	decoded, _, err := transform.Bytes(decoder, data)
	if err != nil {
		return "", fmt.Errorf("解码失败 (%s): %v", charset, err)
	}

	return string(decoded), nil
}

// ThreeInOneMeasurement 实现三合一度量功能
func (s *SoftwareFactoryService) ThreeInOneMeasurement(measurementModel request.MeasurementModel) request.CommandBean {
	reportPath := measurementModel.MeasurementReportPath
	commandBean := request.CommandBean{}

	if reportPath == "" {
		commandBean.ErrorMsg = "传入的度量文件路径为空"
		return commandBean
	}

	fileFound := waitForFileWithTimeout(reportPath, 1*time.Minute)
	if fileFound {
		fmt.Println("操作文件...")

		// 读取文件内容
		data, err := ioutil.ReadFile(reportPath)
		if err != nil {
			commandBean.ErrorMsg = fmt.Sprintf("读取文件失败: %v", err)
			return commandBean
		}

		// 检测编码
		charset, err := detectEncoding(data)
		if err != nil {
			// 检测失败时，尝试使用默认编码
			fmt.Printf("警告: 自动检测编码失败，尝试使用默认编码: %v\n", err)
			charset = "UTF-8"
		}

		fmt.Printf("检测到文件编码: %s\n", charset)

		// 根据编码解码内容
		jsonData, err := decodeByCharset(data, charset)
		if err != nil {
			// 解码失败时，尝试使用其他常见编码
			fmt.Printf("警告: 使用 %s 解码失败，尝试 GB-18030...\n", charset)
			jsonData, err = decodeByCharset(data, "GB-18030")
			if err != nil {
				commandBean.ErrorMsg = fmt.Sprintf("解码失败: %v", err)
				return commandBean
			}
		}

		commandBean.Report = jsonData
	} else {
		fmt.Println("文件未找到，或等待超时。")
		commandBean.ErrorMsg = "文件未找到，或等待超时。"
	}

	return commandBean
}

// ThreeInOneMeasurement 实现三合一度量功能
func (s *SoftwareFactoryService) ThreeInOneMeasurementbak(measurementModel request.MeasurementModel) request.CommandBean {
	reportPath := measurementModel.MeasurementReportPath
	commandBean := request.CommandBean{}

	if reportPath == "" {
		commandBean.ErrorMsg = "传入的度量文件路径为空"
		return commandBean
	}

	fileFound := waitForFileWithTimeout(reportPath, 1*time.Minute)
	if fileFound {
		fmt.Println("操作文件...")
		// 自动检测编码
		data, err := ioutil.ReadFile(reportPath)
		if err != nil {
			commandBean.ErrorMsg = fmt.Sprintf("读取文件失败: %v", err)
			return commandBean
		}
		detector := chardet.NewTextDetector()
		result, err := detector.DetectBest(data)
		if err != nil {
			commandBean.ErrorMsg = fmt.Sprintf("检测编码失败: %v", err)
			return commandBean
		}

		var jsonData string
		switch result.Charset {
		case "UTF-8":
			jsonData = string(data)
		case "GB2312", "GBK":
			decoder := simplifiedchinese.GBK.NewDecoder()
			decoded, _, err := transform.String(decoder, string(data))
			if err != nil {
				commandBean.ErrorMsg = fmt.Sprintf("解码失败: %v", err)
				return commandBean
			}
			jsonData = decoded
		default:
			commandBean.ErrorMsg = fmt.Sprintf("不支持的编码: %s", result.Charset)
			return commandBean
		}

		commandBean.Report = jsonData
	} else {
		fmt.Println("文件未找到，或等待超时。")
		commandBean.ErrorMsg = "文件未找到，或等待超时。"
	}

	return commandBean
}

//
//// ThreeInOneMeasurement 实现三合一度量功能
//func (s *SoftwareFactoryService) ThreeInOneMeasurement(measurementModel request.MeasurementModel) request.CommandBean {
//	reportPath := measurementModel.MeasurementReportPath
//	commandBean := request.CommandBean{}
//
//	if reportPath == "" {
//		commandBean.ErrorMsg = "传入的度量文件路径为空"
//		return commandBean
//	}
//
//	fileFound := waitForFileWithTimeout(reportPath, 120*time.Minute)
//	if fileFound {
//		fmt.Println("操作文件...")
//		jsonData, err := readFileWithEncoding(reportPath, "GB2312")
//		if err != nil {
//			commandBean.Report = "no Measurement json"
//		} else {
//			commandBean.Report = jsonData
//		}
//	} else {
//		fmt.Println("文件未找到，或等待超时。")
//		commandBean.Report = "no Measurement json"
//	}
//
//	return commandBean
//}

// waitForFileWithTimeout 等待文件出现，超时则返回false
func waitForFileWithTimeout(filePath string, timeout time.Duration) bool {
	startTime := time.Now()
	for {
		if _, err := os.Stat(filePath); err == nil {
			fmt.Printf("文件已找到: %s\n", filePath)
			return true
		}

		if time.Since(startTime) > timeout {
			fmt.Printf("等待文件超时: %s\n", filePath)
			return false
		}

		time.Sleep(1 * time.Second)
	}
}

// readFile 读取文件内容
func readFile(filePath string) (string, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	var content string
	for scanner.Scan() {
		content += scanner.Text()
	}

	return content, scanner.Err()
}

// readFileWithEncoding 读取文件内容，支持指定编码
func readFileWithEncoding(filePath, encoding string) (string, error) {
	// 这里简单使用默认编码读取，实际中需要处理GB2312编码
	return readFile(filePath)
}

func NewISoftwareFactoryService() ISoftwareFactoryService {
	return &SoftwareFactoryService{}
}

type ISoftwareFactoryService interface {
	ThreeInOneStaticAnalysis(threeInOneModel request.ThreeInOneModel) request.CommandBean
	ThreeInOneMeasurement(measurementModel request.MeasurementModel) request.CommandBean
}
